// Fill out your copyright notice in the Description page of Project Settings.


#include "VFXChartComponent.h"

#include "Materials/MaterialInstanceDynamic.h"
#include "ChartDataTable.h"
#include "PaletteTable.h"
#include "ProcedrualBarComponent.h"
#include "ProceduralSectorComponent.h"
#include "Components/TextRenderComponent.h"

// Sets default values for this component's properties
UVFXChartComponent::UVFXChartComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;

	// ...
	NeedRebuild = true;
}


// Called when the game starts
void UVFXChartComponent::BeginPlay()
{
	Super::BeginPlay();

	// ...
	
}

void UVFXChartComponent::OnRegister()
{
	Super::OnRegister();

	if (ChartDataTable)
	{
		for (const auto& Iter : ChartDataTable->GetRowMap())
		{
			FChartDataTableRow* Row = reinterpret_cast<FChartDataTableRow*>(Iter.Value);

			FDataValue Value;
			Value.Index = Row->Index;
			Value.Name = Row->Name;
			Value.Value = Row->Value;
		}
	}
}

void UVFXChartComponent::OnUnregister()
{
	Super::OnUnregister();

	if (NeedRebuild)
	{
		for (auto Component : ProcedrualMeshComponents)
		{
			if (Component)
			{
				Component->UnregisterComponent();
				Component->DestroyComponent();
			}
		}

		ProcedrualMeshComponents.Reset();
	}
}

// Called every frame
void UVFXChartComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...
}

void UVFXChartComponent::SetValues(TArray<FDataValue> ValuesArray)
{
	Data = ValuesArray;
}

void UVFXChartComponent::BuildBarChart()
{
	AActor* Owner = this->GetOwner();

	float BaseHeight = 3.0f; 
	
	for (int i = 0; i < Data.Num(); ++i)
	{
		FDataValue Value = Data[i];

		const FPaletteTableRow* PaletteTableRow = nullptr;
		if (PaletteTable)
		{
			const FName RowName = FName(FString::FromInt(Value.Index));
			PaletteTableRow = PaletteTable->FindRow<FPaletteTableRow>(RowName, "");
		}
		
		const auto BarComponent = NewObject<UProcedrualBarComponent>(this, *(Value.Name));
		ProcedrualMeshComponents.Add(BarComponent);

		BarComponent->SetFlags(RF_Transient);
		BarComponent->RegisterComponent();
		Owner->AddInstanceComponent(BarComponent);
		
		BarComponent->AttachToComponent(Owner->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);

		FString LableValueString = "";

		if (Value.Value != 0)
		{
			LableValueString = FString::SanitizeFloat(Value.Value, 0);
		}
		
		BarComponent->Rebuild(50.0f, Value.Value * 30.0f + BaseHeight, Bevel, MaterialInterface,
			Value.Name, LableValueString, TextMaterial);
		const FLinearColor Color = PaletteTableRow ? PaletteTableRow->Color : FLinearColor::MakeRandomColor();
		BarComponent->SetColor(Color);
		
		BarComponent->SetRelativeLocation(FVector::UnitY() * 100.0f * i);
		
	}
}

void UVFXChartComponent::BuildPieChart()
{
	AActor* Owner = this->GetOwner();
	
	float Min = 0;
	float Max = 0;
	FRandomStream RandomStream(FMath::Rand());

	float Sum = 0;

	for (int i = 0; i < Data.Num(); ++i)
	{
		FDataValue Value = Data[i];
		Sum += Value.Value;
	}

	for (int i = 0; i < Data.Num(); ++i)
	{
		FDataValue Value = Data[i];

		if (Value.Value == 0)
		{
			continue;
		}

		const float Percent = Value.Value / Sum;
	
		Max = Min + Percent;
		const FPaletteTableRow* PaletteTableRow = nullptr;
		if (PaletteTable)
		{
			const FName RowName = FName(FString::FromInt(Value.Index));
			PaletteTableRow = PaletteTable->FindRow<FPaletteTableRow>(RowName, "");
		}
			
		const auto SectorComponent = NewObject<UProceduralSectorComponent>(this, *(Value.Name));
		ProcedrualMeshComponents.Add(SectorComponent);

		SectorComponent->SetFlags(RF_Transient);
		SectorComponent->RegisterComponent();
		Owner->AddInstanceComponent(SectorComponent);
		
		SectorComponent->AttachToComponent(Owner->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);

		const float RadiusRandom = RandomStream.FRandRange(0.1f, 10.0f);
		const float HeightRandom = RandomStream.FRandRange(0, 0.5f);
		
		SectorComponent->Rebuild(Percent * 360.0f, Radius + RadiusRandom, Height + HeightRandom, 100, Bevel, MaterialInterface);
		const FLinearColor Color = PaletteTableRow ? PaletteTableRow->Color : FLinearColor::MakeRandomColor();
		SectorComponent->SetColor(Color);

		const auto Mid = (Min + Max) / 2.0f;
		SectorComponent->SetRelativeRotation(FRotator(0.0f, Mid * 360.0f, 0.0f));
		
		FQuat RotationQuat = FQuat(FVector::UnitZ(), FMath::DegreesToRadians((Mid) * 360.0f));
		FVector RotatedVector = RotationQuat.RotateVector(FVector::UnitX());
		SectorComponent->SetRelativeLocation(RotatedVector * CenterOffset);
		
		SectorComponent->SetLabel(FString::FromInt(Value.Value), LabelRadiusPos,  Mid * 360.0f - 180.0f, TextMaterial);

		Min = Max;
	}
}

#if WITH_EDITOR
void UVFXChartComponent::PreEditChange(FProperty* PropertyThatWillChange)
{
	Super::PreEditChange(PropertyThatWillChange);

	if (PropertyThatWillChange)
	{
		FName PropertyName = PropertyThatWillChange->GetFName();

		if (PropertyName == GET_MEMBER_NAME_CHECKED(UVFXChartComponent, ChartDataTable))
		{
			NeedRebuild = true;
		}
	}
}
#endif
